/*+***********************************************************************************
 Filename: A01_tinyriscv_mcu01\src\perips\peripheral_uart.v
 Description: a simple uart peripheral module.

 Modification:
   2022.11.08 Creation   H.Zheng  (03_tinycore_step05)
   2024.02.02 change addr to 4 bits  H.Zheng  (A01_tinyriscv_mcu01)
              change uart_tx to simpleuart with tx and rx
   2024.05.23 seperate rx_valid flag and tx_busy flag to two regs
   2024.05.24 add int_rx_valid_o port

Copyright (C) 2022  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/

/**
 * I/O Regs:
 *  offset      reg
 * 0x00         UART_TXD  
 * 0x00         UART_RXD  
 * 0x04         rx_valid status (bit0)
 * 0x08         tx_busy status  (bit0)
 */

module peripheral_uart (
    input wire clk,
    input wire reset_n,
    input wire rxd,
    output wire txd,
    input wire ce, //chip enable
    input wire wre, //write enable
    input wire [3:0] addr, //address bus [5:2]
    input wire [31:0] data_in,
    output wire [31:0] data_out,
    output wire int_rx_valid_o

);

    reg [31:0] data_tx_reg;

    wire uart_tx_en = ce & wre & (addr==2'b00);

    //write data_tx_reg register
    always @(posedge clk) begin
        if (~reset_n) begin
            data_tx_reg <= 32'b0;
        end
        else if (uart_tx_en) begin
            data_tx_reg <= data_in;
        end
    end    

    //generate tx pulse
    reg [1:0] shift_reg;
    always @(posedge clk) begin
        if (~reset_n) begin
            shift_reg <= 2'b0;
        end
        else begin
            shift_reg <= {shift_reg[0], uart_tx_en};
        end
    end    
    wire uart_tx_en_pulse = (shift_reg[1] == 0) & (shift_reg[0] == 1);
    
    //rx ctrl&status signal
    wire rx_data_en = ce & (~wre) & (addr==4'b00);
    wire [31:0] rx_data;
    wire status_rx_rd_en = ce & (~wre) & (addr==4'b0001);
    wire status_tx_rd_en = ce & (~wre) & (addr==4'b0010);
    wire status_tx_busy, status_rx_valid;

    reg [31:0] data_rx_reg;
    always @(posedge clk) begin
        if (~reset_n) begin
            data_rx_reg <= 32'b0;
        end
        else if (rx_data_en) begin
            data_rx_reg <= rx_data;
        end
    end   
    //
//    simpleuart #(.BAUDRATE_DIVIDER(234)) u_simpleuart (
    simpleuart #(.BAUDRATE_DIVIDER(117)) u_simpleuart ( //core_clk=13.5MHz, 13.5M/115200=117.1875
     .clk(clk),
     .reset_n(reset_n),
     .ser_tx(txd),
     .ser_rx(rxd),
     .reg_dat_we(uart_tx_en_pulse),
     .reg_dat_di(data_tx_reg),
     .reg_dat_re(rx_data_en),
     .reg_dat_do(rx_data),
     .tx_busy(status_tx_busy),
     .rx_valid(status_rx_valid)
    );

    //
    assign data_out = rx_data_en ? data_rx_reg :
                      status_rx_rd_en ? {31'b0, status_rx_valid} : 
                      status_tx_rd_en ? {31'b0, status_tx_busy} : 32'b0;

    //int request
    assign int_rx_valid_o = status_rx_valid;

endmodule
